# 导入(new/init文件中的)蓝图
from flask import g

from info import db
from info.models import User, Category, News
from info.utils.response_code import RET
from . import news_blue
from flask import session, render_template, current_app, jsonify, request
# 导入常量
from info.constants import *
# 导入用户登录状态装饰器
from info.utils.commons import login_required


# 使用模板加载项目首页
@news_blue.route('/')
@login_required
def index():
    """
    项目首页
    将右上角检查用户状态和新闻分类的数据传到首页模板index.html用于展示
    """

    # '''
    # 首页右上角用户信息展示(检查用户登录状态)
    # 1、从redis中获取user_id
    # 2、根据user_id查询mysql,获取用户信息
    # :return:
    # '''
    # # 从redis中获取user_id
    # user_id = session.get('user_id')
    # # 判断user_id是否存在(是否登录)(检查用户登录状态)
    # # 如果存在，查询mysql
    # user = None # 防止出现异常后后面调用报错
    # if user_id:
    #     try:
    #         user = User.query.get(user_id)
    #     except Exception as e:
    #         current_app.logger.error(e)
    user = g.user

    '''
    新闻分类信息
    1、从数据库中查询新闻分类信息
    2、判断查询结果
    3、将分类信息传给模板
    '''
    # 从数据库中查询新闻分类
    try:
        categories = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询分类信息失败')
    # 判断分类结果
    if not categories:
        return jsonify(errno=RET.NODATA, errmsg='没有分类信息')

    '''
    新闻点击排行
    1、从数据库中分页查找(按点击数量降序排列)
    2、判断查询结果
    3、将排行信息传给前端
    '''
    # 从数据库中查找
    try:
        news_click = News.query.order_by(News.clicks.desc()).limit(CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='点击排行查询失败')
    # 判断查询结果
    if not news_click:
        return jsonify(errno=RET.NODATA, errmsg='没有点击排行信息')

    # 定义字典数据，(将用户信息)传给模板
    # to_dict模板类里的方法
    data = {
        'user_info': user.to_dict() if user else None,
        'categories': categories,
        'news_click': news_click,
    }
    return render_template('news/index.html', data=data)


@news_blue.route('/news_list')
def news_list():
    '''
    新闻列表
    1、获取参数cid分类id、page页数(默认第一页)、per_page每页个数(默认10个)
    2、把参数转化为同一种类型
    3、根据分类id查找新闻
    4、判断是否查找到新闻
    5、将查找到的新闻返回前端
    '''
    # 从数据库中查找新闻信息
    # 获取参数(给参数加上默认值)
    cid = request.args.get('cid', '1')
    page = request.args.get('page', '1')
    per_page = request.args.get('per_page', '10')
    # 把传入的参数转化为整形值
    try:
        cid, page, per_page = int(cid), int(page), int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数类型错误')
    # 过滤，将不是最新放在列表里
    filters = [News.status == '0']
    if cid > 1:
        filters.append(News.category_id == cid)
    # 根据过滤条件查找新闻
    try:
        paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page, per_page, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询新闻列表失败')
    # 使用分页对象获取分页后的新闻数据
    news = paginate.items
    total_page = paginate.pages
    current_page = paginate.page
    # 遍历新闻列表，调用模型类的to_dict方法
    news_dict_list = []
    for i in news:
        news_dict_list.append(i.to_dict())
    # 返回数据
    data = {
        'news_dict_list': news_dict_list,
        'total_page': total_page,
        'current_page': current_page
    }
    return jsonify(errno=RET.OK, errmsg='OK', data=data)


# 新闻详情页
@news_blue.route('/<int:news_id>')
@login_required
def get_news_detdil(news_id):
    '''

    :param news_id:
    :return:
    '''
    # (检查用户登录状态)
    user = g.user

    '''
        新闻点击排行
        1、从数据库中分页查找(按点击数量降序排列)
        2、判断查询结果
        3、将排行信息传给前端
        '''
    # 从数据库中查找
    try:
        news_click = News.query.order_by(News.clicks.desc()).limit(CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='点击排行查询失败')
    # 判断查询结果
    if not news_click:
        return jsonify(errno=RET.NODATA, errmsg='没有点击排行信息')

    '''
    详情页面数据展示
    1、根据news_id查找新闻
    2、判断是否查找到
    3、返回数据
    '''
    # 从数据库查找
    try:
        news_data = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='新闻详情查询失败')
    # 判断是否找到
    if not news_data:
        return jsonify(errno=RET.NODATA, errmsg='没有新闻详情')

    '''
        用户是否收藏
        1、判断用户是否登录
        2、已登录用户收藏新闻里是否有这个新闻
    '''
    # 定义标记，用来判断用户是否已收藏
    is_collected = False
    # 如果用户登录且已经收藏
    if user and news_data in user.collection_news:
        is_collected = True

    # 定义字典数据，(将用户信息)传给模板
    # to_dict模板类里的方法
    data = {
        'user_info': user.to_dict() if user else None,
        'news_click': news_click,
        'news_detail': news_data.to_dict(),
        'is_collected': is_collected
    }
    return render_template('news/detail.html', data=data)


# 新闻收藏
@news_blue.route('/news_collect', methods=['POST'])
@login_required
def news_collect():
    '''
    新闻收藏和取消收藏
    1、判断用户是否登录
    2、获取参数news_id(新闻id)action(collect,cancel_collect)
    3、检查参数的完整性
    4、转换news_id数据类型
    5、检查action必须为收藏或取消收藏
    6、根据news_id查询新闻
    7、判断是否查询到新闻
    8、判断用户选择的是收藏还是取消收藏
    9、收藏情况下存储新闻到收藏列表
    10、取消收藏情况下把新闻从收藏列表删除
    11、提交数据
    12、返回结果
    :return:
    '''
    # 判断用户是否登录
    user = g.user   # 从登录验证装饰器获取用户信息
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg='用户未登录')
    # 获取参数
    news_id = request.json.get('news_id')
    action = request.json.get('action')
    # 检查参数完整性
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    # 转换news_id数据类型
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数类型错误')
    # 判断action必须为收藏或取消收藏
    if action not in ['collect', 'cancel_collect']:
        return jsonify(errno=RET.PARAMERR, errmsg='参数格式错误')
    # 根据news_id查询新闻
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询新闻错误')
    # 判断查询结果
    if not news:
        return jsonify(errno=RET.NODATA, errmsg='没有新闻信息')
    # 如果收藏
    if action == 'collect':
        user.collection_news.append(news)
    # 取消收藏
    else:
        user.collection_news.remove(news)
    # 提交数据
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='提交数据失败')
    # 返回结果
    return jsonify(errno=RET.OK, errmsg='OK')


# 项目logo图标加载
@news_blue.route('/favicon.ico')
def favicon():
    '''
    浏览器不是每次请求都加载logo图标，实现代码后:
        1、清除浏览器的浏览信息和缓存
        2、让浏览器重新启动(彻底退出)
    :return:
    '''
    # 通过current_app调用Flask框架内部的发送静态文件给浏览器的函数send_static_file
    return current_app.send_static_file('news/favicon.ico')